package com.wits100.av;


import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.util.Log;

import java.nio.ByteBuffer;

/**
 * Created by zhengboyuan on 2016-12-28.
 */

public class SimpleAudioRender implements AudioRender {

    private static final int TIMEOUT_US = 1000 * 10;
    private static final String TAG = "player";


    private MediaCodec codec;
    private MediaFormat mediaFormat;
    private MFormat fmt;

    private AudioTrack audioTrack;
    private MediaCodec.BufferInfo bufferInfo;


    public SimpleAudioRender() {

    }

    @Override
    public boolean open(MFormat fmt) {
        this.fmt = fmt;

        boolean ret = openCodec(fmt);
        if (ret) {
            openAudioTrack();
        }

        return ret;
    }

    @Override
    public void close() {

        closeCodec();

        closeAudioTrack();
    }

    @Override
    public boolean isOpen() {
        return isCodecOpen();
    }

    @Override
    public void input(MPacket pkt) {

        synchronized (this) {

            if (!isCodecOpen()) {
                return;
            }

            doInput(pkt);

            doRender();
        }

    }


    private boolean openCodec(MFormat fmt) {
        closeCodec();

        try {
            if (fmt.audioCodec <= 0) {
                return false;
            }

            mediaFormat = fmt.toAudioFormat();

            String mime = mediaFormat.getString(MediaFormat.KEY_MIME);

            codec = MediaCodec.createDecoderByType(mime);
            codec.configure(mediaFormat, null, null, 0);
            codec.start();

            return true;
        } catch (Throwable e) {
            if (codec != null) {
                codec.release();
                codec = null;
            }

            e.printStackTrace();
        }
        return false;
    }

    private void closeCodec() {
        if (codec != null) {
            try {
                codec.stop();
                codec.release();
            } finally {
                codec = null;
            }
        }
    }

    private boolean isCodecOpen() {
        return codec != null;
    }


    private void openAudioTrack() {
        bufferInfo = new MediaCodec.BufferInfo();

        int channelConfig = (fmt.channels == 2) ? AudioFormat.CHANNEL_OUT_STEREO : AudioFormat.CHANNEL_OUT_MONO;
        int buffsize = AudioTrack.getMinBufferSize(fmt.sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT);
        // 创建AudioTrack对象
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, fmt.sampleRate,
                channelConfig,
                AudioFormat.ENCODING_PCM_16BIT,
                buffsize,
                AudioTrack.MODE_STREAM);
        //启动AudioTrack
        audioTrack.play();
    }

    private void closeAudioTrack() {
        if (audioTrack != null) {
            audioTrack.release();
            audioTrack = null;
        }
    }

    private void doInput(MPacket pkt) {
        try {
            ByteBuffer[] buffers = codec.getInputBuffers();
            int inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_US);
            if (inputBufIndex >= 0) {
                ByteBuffer inputBuf = buffers[inputBufIndex];
                inputBuf.clear();
                inputBuf.put(pkt.data);

                codec.queueInputBuffer(inputBufIndex, 0, pkt.length(), pkt.ts, pkt.flags);
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private void doRender() {

        int outIndex = codec.dequeueOutputBuffer(bufferInfo, 0);
        switch (outIndex) {
            case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED");
                break;

            case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                MediaFormat format = codec.getOutputFormat();
                Log.d(TAG, "New format " + format);
                audioTrack.setPlaybackRate(format.getInteger(MediaFormat.KEY_SAMPLE_RATE));

                break;
            case MediaCodec.INFO_TRY_AGAIN_LATER:
                Log.d(TAG, "dequeueOutputBuffer timed out!");
                break;

            default:
                ByteBuffer[] outputBuffers = codec.getOutputBuffers();
                ByteBuffer outBuffer = outputBuffers[outIndex];
                //Log.v(TAG, "outBuffer: " + outBuffer);

                final byte[] chunk = new byte[bufferInfo.size];
                // Read the buffer all at once
                outBuffer.get(chunk);
                //清空buffer,否则下一次得到的还会得到同样的buffer
                outBuffer.clear();

                // AudioTrack write data
                int count = audioTrack.write(chunk, 0, bufferInfo.size);
                if (count != bufferInfo.size)
                {
                    Log.w(TAG, "audio track write return: " + count);
                }

                codec.releaseOutputBuffer(outIndex, false);
                break;
        }

    }


}

